<?php

Yii::import("application.components.evaluators.Sandbox");

class Compiler {

    private $request;
    private $tmpFile = null;
    private $dir = "";

    public function __construct($pRequest) {
        $this->request = $pRequest;
    }

    public function compileSource(&$output) {
        $this->tmpFile = tempnam("/var/lz/temp" , "lz-");
        file_put_contents($this->tmpFile , $this->request->file);
        
        ///Unzipping
        $this->dir = "/var/lz/temp/" . $this->request->id;
        exec("unzip " . $this->tmpFile . " -d $this->dir");
        
        exec("make -f $this->dir/Makefile -C $this->dir 2>&1" , $out , $return);
        
        $output = implode("\n" , $out);
        
        return $return;
    }
    
    public function cleanup() {
        if ($this->tmpFile != null)
            exec("rm -rf " . $this->tmpFile);
        if ($this->dir != "") {
            exec("rm -rf $this->dir");
        }
    }

    public static function compile($sourcepath, $sourcelang, $outputpath = NULL, $parameter = NULL, &$compiler_output) {
        $compiletimelimit = 2;
        $compilememorylimit = 64000;
        $parameter = (!is_null($parameter) && isset($parameter[$sourcelang])) ? $parameter[$sourcelang] : '';
        if (is_null($outputpath)) {
            $outputpath = Sandbox::getTempName();
        }
        $compiler_gcc_path = Yii::app()->params->config['evaluator']['compiler']['compiler_gcc_path'];
        $compiler_cpp_path = Yii::app()->params->config['evaluator']['compiler']['compiler_cpp_path'];
        $compiler_fpc_path = Yii::app()->params->config['evaluator']['compiler']['compiler_fpc_path'];

        switch ($sourcelang) {
            case 'pp' :
            case 'pas' :
                $compilecmd = sprintf("%s %s -o%s %s", $compiler_fpc_path, $parameter, $outputpath, $sourcepath
                );
                break;
            case 'c++' :
            case 'cpp' :
                $compilecmd = sprintf("%s -x c++ %s -o %s %s -O2", $compiler_cpp_path, $parameter, $outputpath, $sourcepath
                );
                break;
            case 'c' :
                $compilecmd = sprintf("%s -x c -std=c99 %s -o %s %s", $compiler_gcc_path, $parameter, $outputpath, $sourcepath
                );
                break;
            default :
                echo " Error in grading: Source language not recognized\n";
                throw new CompilerException(CompilerException::ERR_LANGUAGE_UNRECOGNIZED);
                break;
        }
        $sandboxparam = sprintf("-e -m %s -t %s", $compilememorylimit, $compiletimelimit);
        $sandboxexec = $compilecmd;
        $sandboxoutput = "";
        $retval = 0;
        try {
            Sandbox::execute($sandboxparam, $sandboxexec, &$sandboxoutput, &$retval);
            $compiler_output = $sandboxoutput;
        } catch (SandboxException $ex) {
            $compiler_output = $sandboxoutput;
            throw new CompilerException(CompilerException::ERR_COMPILE_ERROR);
        }

        if ($retval != 0) {
            throw new CompilerException(CompilerException::ERR_COMPILE_ERROR);
        }
        if ($sourcelang == 'pascal') {
            unlink($sourcepath . ".o");
        }
        return $outputpath;
    }

}
